﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;

namespace Kazuku.Core.Models {
	public class AssemblyResource {
		public string VirtualPath { get; set; }
		public string Namespace { get; set; }
		public Type TypeToLocateAssembly { get; set; }
		public string GetFullyQualifiedTypeFromPath(string path) {
			string replace = path.ToLower().Replace("~", Namespace.ToLower());
			if (!string.IsNullOrEmpty(VirtualPath))
				replace = replace.Replace(VirtualPath.ToLower(), "");
			return replace.Replace("/", ".").ToLower();
		}

		public string GetResourceNameFromPath(string path) {
			var name = GetFullyQualifiedTypeFromPath(path);
			return TypeToLocateAssembly.Assembly.GetManifestResourceNames().Where(s => s.ToLower().Equals(name)).FirstOrDefault();
		}


	}
	public class KazukuVirtualPathProvider : VirtualPathProvider {
		static KazukuVirtualPathProvider() {
			ResourcePaths = new Dictionary<string, AssemblyResource>();
		}
		public KazukuVirtualPathProvider() : this(new Hashtable()) {}
		public KazukuVirtualPathProvider(Hashtable siteTemplates) {
			//ResourcePaths = new Dictionary<string, AssemblyResource>();
			SiteTemplates = siteTemplates;
		}
		
		public static void AddResource(AssemblyResource assemblyResource) {
			ResourcePaths.Add(assemblyResource.VirtualPath, assemblyResource);
		}
		

		private static Dictionary<string, AssemblyResource> ResourcePaths { get; set; }
		private static Hashtable SiteTemplates { get; set; }

		public void AddSiteTemplate(string viewName, byte[] body) {
			if (!SiteTemplates.ContainsKey(viewName)) {
				SiteTemplates.Add(viewName, body);
			}
		}

		public bool IsAppResourcePath(string virtualPath) {

			String checkPath = VirtualPathUtility.ToAppRelative(virtualPath).ToLower();
			foreach (var resourcePath in ResourcePaths) {
				if (checkPath.Contains(resourcePath.Key) &&
					ResourceExists(resourcePath.Value, checkPath))
					return true;
			}
			return false;
		}

		private bool ResourceExists(AssemblyResource assemblyResource, string path) {
			var name = assemblyResource.GetFullyQualifiedTypeFromPath(path);
			return assemblyResource.TypeToLocateAssembly.Assembly.GetManifestResourceNames().Any(s => s.ToLower().Equals(name));
		}


		public AssemblyResource GetResource(string virtualPath) {
			String checkPath = VirtualPathUtility.ToAppRelative(virtualPath).ToLower();
			foreach (var resourcePath in ResourcePaths) {
				if (checkPath.Contains(resourcePath.Key))
					return resourcePath.Value;
			}
			return null;
		}

		public override bool FileExists(string virtualPath) {
			// [new]
			//var dynamicTemplate = FindDynamicTemplate(virtualPath);
			//if (dynamicTemplate != null) {
			if (SiteTemplates.ContainsKey(virtualPath)) {
				return true;
			}
			else {
				bool exists = base.FileExists(virtualPath);
				return exists ? exists : IsAppResourcePath(virtualPath);
			}
			// [new end]
			//bool exists = base.FileExists(virtualPath);
			//return exists ? exists : IsAppResourcePath(virtualPath);
		}

		public override VirtualFile GetFile(string virtualPath) {
			// [new]
			//var dynamicTemplate = FindDynamicTemplate(virtualPath);
			//if (dynamicTemplate != null) {
			if (SiteTemplates.ContainsKey(virtualPath)) {
				return new DynamicTemplateVirtualFile(virtualPath, (byte[]) SiteTemplates[virtualPath]);
			}
			// [new end]
			if (IsAppResourcePath(virtualPath) && !base.FileExists(virtualPath)) {
				var resource = GetResource(virtualPath);// ResourcePaths[virtualPath.ToLower()];
				return new AssemblyResourceVirtualFile(virtualPath, resource);
			}
			else {
				return base.GetFile(virtualPath);
			}
		}

		public override CacheDependency GetCacheDependency(string virtualPath,
														   IEnumerable virtualPathDependencies,
														   DateTime utcStart) {
			if (IsAppResourcePath(virtualPath)) {
				return null;
			}
			else {
				string[] dependencies = virtualPathDependencies.OfType<string>().ToArray();
				return base.GetCacheDependency(virtualPath,
											   dependencies, utcStart);
			}
		}

		public override string GetCacheKey(string virtualPath) {
			return null;
		}
		
		// [new] dynamic template methods
		//private DynamicTemplate FindDynamicTemplate (string virtualPath) {
		//    DynamicTemplate dynamicTemplate = DynamicTemplates.Find(t => t.ViewName == virtualPath);
		//    return dynamicTemplate;
		//}
		public void RemoveSiteTemplate(string viewPath) {
			if (!SiteTemplates.ContainsKey(viewPath)) {
				SiteTemplates.Remove(viewPath);
			}
		}
	}
	
}
